package com.jy.appmarket.download;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.jy.app.market.idata.card.CardUpgrade;
import com.jy.app.market.idata.data.Upgrade;
import com.jy.appmarket.R;
import com.jy.appmarket.activity.DownloadManagerActivity;
import com.jy.appmarket.database.AppUpdateDatabase;
import com.jy.appmarket.download.DownloadThread.DownloadThreadListener;
import com.jy.appmarket.model.AppUpdateModel;
import com.jy.appmarket.service.UpdateService;
import com.jy.appmarket.statistics.event.downloadSuccessEvent;
import com.jy.appmarket.statistics.event.installEvent;
import com.jy.appmarket.statistics.event.startDownloadEvent;
import com.jy.appmarket.statistics.event.waitWifiDownloadEvent;
import com.jy.appmarket.statistics.umeng.myUmengStaticstics;
import com.jy.appmarket.utils.Command;
import com.jy.appmarket.utils.Command.CommandListener;
import com.jy.appmarket.utils.LogUtil;
import com.jy.appmarket.utils.PackageUtils;
import com.rad.statistics.android.StatisticsAgent;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.os.Binder;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

public class DownloadService extends Service implements DownloadThreadListener {
	private static final String TAG = "DownloadService";

	public static final String ACTION_START_DOWNLOAD = "com.jy.appmarket.ACTION.START_DOWNLOAD";
	public static final String ACTION_START_INSTALL = "com.jy.appmarket.ACTION.START_INSTALL";
	public static final String ACTION_RESUME_DOWNLOAD = "com.jy.appmarket.ACTION.RESUME_DOWNLOAD";

	public static final String EXTRA_DOWNLOADMODEL = "download_model";
	public static final String EXTRA_OPEN_DOWNLOADMGR = "open_download_mgr";

	private static final int MAX_DOWNLOAD = 2;
	private static final int MAX_RETRY_COUNT = 3;

	// init status
	public static final int STATUS_NO_STATUS = 1;
	public static final int STATUS_PENDING = 2;

	// downloading status
	public static final int STATUS_PREPARE_TO_DOWNLOAD = 4;
	public static final int STATUS_DOWNLOADING = 5;
	public static final int STATUS_PREPARE_TO_STOP = 6;

	// stopped status
	public static final int STATUS_PAUSED_BY_MOBILE_NETWORK = 7;
	public static final int STATUS_PAUSED_BY_USER = 8;
	public static final int STATUS_PAUSED_BY_ERROR = 9;
	public static final int STATUS_DOWNLOAD_FINISHED = 10;

	/** 不会出现在数据库中 */
	public static final int STATUS_CAN_INSTALL = 11;
	/** 不会出现在数据库中 */
	public static final int STATUS_INSTALLED = 12;
	/** 静默安装时使用 */
	public static final int STATUS_INSTALLING = 13;

	/**
	 * 下载管理中的任务因为版本不正确而过期不可用了。 出现的情况比如在榜单A中的某App版本号是1，而相同App在榜单B中的版本号是2.
	 * 当在榜单A中已经将这个App加入到下载管理后，在榜单B中获取该App的状态就是out_of_date
	 * 
	 * 当用户点击后的处理方式为：删除之前下载管理中的任务，将当前榜单中的任务加入下载管理中。
	 * 此种处理方式不会判断两个榜单中的App的版本号高低，均以当前榜单中数据为准。 保证了下载管理中，相同包名的任务只有一个。
	 */
	public static final int STATUS_DOWNLOAD_OUT_OF_DATE = 14;

	/** 该应用可以更新 */
	public static final int STATUS_NEED_TO_UPDATE = 15;

	public static String getStatusString(int status) {
		switch (status) {
		case STATUS_NO_STATUS:
			return "无";
		case STATUS_PENDING:
			return "排队中";
		case STATUS_PREPARE_TO_DOWNLOAD:
			return "准备下载";
		case STATUS_DOWNLOADING:
			return "下载中";
		case STATUS_PREPARE_TO_STOP:
			return "准备停止";
		case STATUS_PAUSED_BY_MOBILE_NETWORK:
			return "移动网络等待";
		case STATUS_PAUSED_BY_USER:
			return "用户暂停";
		case STATUS_PAUSED_BY_ERROR:
			return "下载出错";
		case STATUS_DOWNLOAD_FINISHED:
			return "下载完成";
		case STATUS_CAN_INSTALL:
			return "准备安装";
		case STATUS_INSTALLED:
			return "已安装";
		case STATUS_INSTALLING:
			return "安装中";
		default:
			return "未知状态:" + status;
		}
	}

	private Map<String, DownloadThread> mDownloads = new HashMap<String, DownloadThread>();
	private List<FileDownloadListener> mListeners = new ArrayList<FileDownloadListener>();
	private Set<String> mInstallingTask = new HashSet<String>();
	private CheckDlUpgradeReceiver mCheckDlUpgradeReceiver = new CheckDlUpgradeReceiver();
	private final DLServiceBinder mBinder = new DLServiceBinder();

	public interface FileDownloadListener {
		void onDownloadCreated(DownloadItem di);

		void onDownloadChanged(DownloadItem di);

		void onDownloadRemoved(String id);

		void onProgressChanged(String id, long downloadedBytes, long speed);
	}

	public class DLServiceBinder extends Binder {
		public DownloadService getService() {
			return DownloadService.this;
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

	@Override
	public void onCreate() {
		super.onCreate();

		registerBroadcastReceiver();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (intent == null) {
			return super.onStartCommand(intent, flags, startId);
		}
		if (ACTION_RESUME_DOWNLOAD.equals(intent.getAction())) {
			Log.d(TAG, "resume download");
			startNext();

		} else if (ACTION_START_INSTALL.equals(intent.getAction())) {
			DownloadItem item = intent.getParcelableExtra(EXTRA_DOWNLOADMODEL);
			installApk(item);
		} else if (ACTION_START_DOWNLOAD.equals(intent.getAction())) {
			DownloadItem item = intent.getParcelableExtra(EXTRA_DOWNLOADMODEL);
			boolean isOpenDownLoadMgr = intent.getBooleanExtra(EXTRA_OPEN_DOWNLOADMGR, false);
			addDownload(item, isOpenDownLoadMgr);
		}
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		LogUtil.d(TAG, "onDestroy");
		super.onDestroy();
		for (String id : mDownloads.keySet()) {
			DownloadThread dt = mDownloads.get(id);
			if (dt.isDownloading()) {
				dt.stopDownload();
			}
		}

		if (mCheckDlUpgradeReceiver != null) {
			unregisterReceiver(mCheckDlUpgradeReceiver);
			mCheckDlUpgradeReceiver = null;
		}
	}

	// ///////////////////////////////////////////////////////////////////////////////
	// download thread callbacks start
	// //////////////////////////////////////////////////////////////////////////////
	@Override
	public void OnDownloadConnected(String id, long bytes) {
		// Log.d(TAG, "OnDownloadConnected:" + id + " size:" + bytes);
		DownloadItem di = getDownloadById(id);
		if (di == null) {
			Log.d(TAG, "OnDownloadConnected:" + id + " not found in db");
			return;
		}
		di.setTotalSize(bytes);
		di.setStatus(STATUS_DOWNLOADING);
		updateDatabase(di);
		if (mListeners != null) {
			for (FileDownloadListener l : mListeners) {
				l.onDownloadChanged(di);
			}
		}
	}

	@Override
	public void onDownloadFinished(String id) {
		// Log.d(TAG, "onDownloadFinished:" + id);
		DownloadItem di = getDownloadById(id);
		if (di == null) {
			Log.d(TAG, "onDownloadFinished:" + id + " not found in db");
			return;
		}
		myUmengStaticstics.successDownload(getApplicationContext(), di.getSource(), di.getPkgName());
		StatisticsAgent.onEvent(getApplicationContext(), new downloadSuccessEvent(di.getSource(), di.getPkgName()));
		di.setStatus(STATUS_DOWNLOAD_FINISHED);
		updateDatabase(di);
		DownloadThread dt = mDownloads.get(id);
		if (dt != null) {
			mDownloads.remove(id);
			dt.setDownloadListener(null);
			dt.stopDownload();
			dt = null;
		}

		if (mListeners != null) {
			for (FileDownloadListener l : mListeners) {
				l.onDownloadChanged(di);
			}
		}
		installApk(di);
		startNext();
	}

	@Override
	public void OnUpdateProgress(String id, long downloadedBytes, long speed) {
		// Log.d(TAG, "OnUpdateProgress:" + id + " downloaded:" +
		// downloadedBytes + " speed:"
		// + Formatter.formatFileSize(this, speed));
		if (mListeners == null) {
			return;
		}
		for (FileDownloadListener l : mListeners) {
			l.onProgressChanged(id, downloadedBytes, speed);
		}
	}

	@Override
	public void OnPausedByUser(String id) {
		// Log.d(TAG, "OnPausedByUser:" + id);
		DownloadItem di = getDownloadById(id);
		if (di == null) {
			Log.d(TAG, "OnPausedByUser:" + id + " not found in db,maybe removed");
			return;
		}
		myUmengStaticstics.stopDownload(getApplicationContext(), di.getSource(), di.getPkgName(), "user");
		// 删除任务
		if (di.isShouldRemove()) {
			DownloadDatabase db = DownloadDatabase.getInstance(this);
			db.deleteById(id);
			DownloadUtils.removeDownloadTmpFile(id);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadRemoved(id);
				}
			}
			return;
		}
		di.setStatus(STATUS_PAUSED_BY_USER);
		File tmp = new File(DownloadUtils.getDownloadApkTmpFilePathById(id));
		di.setDownloadedSize(tmp.length());
		updateDatabase(di);
		DownloadThread dt = mDownloads.get(id);
		if (dt != null) {
			mDownloads.remove(id);
			dt.setDownloadListener(null);
			dt.stopDownload();
			dt = null;
		}
		if (mListeners != null) {
			for (FileDownloadListener l : mListeners) {
				l.onDownloadChanged(di);
			}
		}
		startNext();
	}

	@Override
	public void onPausedByError(String id, long detail) {
		// Log.d(TAG, "onPausedByError:" + id + " detail:" + detail);
		DownloadItem di = getDownloadById(id);
		if (di == null) {
			Log.d(TAG, "onPausedByError:" + id + " not found in db");
			return;
		}
		myUmengStaticstics.stopDownload(getApplicationContext(), di.getSource(), di.getPkgName(), "error:" + detail);
		di.setRetryCount(di.getRetryCount() + 1);
		Log.d(TAG, id + " retry:" + di.getRetryCount());
		di.setStatus(STATUS_PAUSED_BY_ERROR);
		File tmp = new File(DownloadUtils.getDownloadApkTmpFilePathById(id));
		di.setDownloadedSize(tmp.length());
		updateDatabase(di);
		DownloadThread dt = mDownloads.get(id);
		if (dt != null) {
			mDownloads.remove(id);
			dt.setDownloadListener(null);
			dt.stopDownload();
			dt = null;
		}

		if (mListeners != null) {
			for (FileDownloadListener l : mListeners) {
				l.onDownloadChanged(di);
			}
		}
		startNext();
	}

	// ///////////////////////////////////////////////////////////////////////////////
	// 以下函数通过DownloadActivity对外提供，仅供继承与DownloadActivity的Activity使用//
	// //////////////////////////////////////////////////////////////////////////////
	boolean isDownloading(DownloadItem di) {
		if (mDownloads == null) {
			return false;
		}

		if (di == null || di.getId() == null) {
			return false;
		}

		return mDownloads.containsKey(di.getId());
	}

	boolean isDownloading(String packageName, int versionCode) {
		if (mDownloads == null) {
			return false;
		}

		if (TextUtils.isEmpty(packageName)) {
			return false;
		}

		return mDownloads.containsKey(DownloadUtils.generateDownloadId(packageName, versionCode));
	}

	void addWaitWifiDownload(String dlUrl, String name, String pkgName, String versionName, int versionCode, String md5,
			String iconUrl, String source, int priority, boolean hidden) {
		String dlId = DownloadUtils.generateDownloadId(pkgName, versionCode);
		DownloadItem di = getDownloadById(dlId);
		if (di != null) {
			Log.w(TAG, "download:" + dlUrl + " already exists");
			return;
		}
		myUmengStaticstics.waitWifiDownload(getApplicationContext(), source, pkgName);
		long id = insertToDatabase(dlUrl, name, pkgName, versionName, versionCode, md5, iconUrl, priority, source,
				hidden);
		if (id == -1) {
			Log.w(TAG, "insert failed:" + dlUrl);
			return;
		}
		di = getDownloadById(dlId);
		di.setStatus(STATUS_PAUSED_BY_MOBILE_NETWORK);
		updateDatabase(di);
		if (mListeners != null) {
			for (FileDownloadListener l : mListeners) {
				l.onDownloadCreated(di);
			}
		}
		StatisticsAgent.onEvent(getApplicationContext(), new waitWifiDownloadEvent(source, pkgName));
	}

	void addDownload(String dlUrl, String name, String pkgName, String versionName, int versionCode, String md5,
			String iconUrl, String source, int priority, boolean hidden) {

		if (TextUtils.isEmpty(source)) {
			LogUtil.w(TAG, "empty source of " + name);
		}
		myUmengStaticstics.startDownload(getApplicationContext(), source, pkgName);
		String dlId = DownloadUtils.generateDownloadId(pkgName, versionCode);
		DownloadItem di = getDownloadById(dlId);
		if (di != null) {
			Log.w(TAG, "download:" + dlUrl + " already exists");
			return;
		}

		long id = insertToDatabase(dlUrl, name, pkgName, versionName, versionCode, md5, iconUrl, priority, source,
				hidden);
		if (id == -1) {
			Log.w(TAG, "insert failed:" + dlUrl);
			return;
		}
		DownloadThread dt = mDownloads.get(dlId);
		if (dt != null) {
			Log.w(TAG, dlId + " should not in running task");
			mDownloads.remove(dlId);
			dt.setDownloadListener(null);
			dt.stopDownload();
		}
		di = getDownloadById(dlId);
		if (mListeners != null) {
			for (FileDownloadListener l : mListeners) {
				l.onDownloadCreated(di);
			}
		}

		// 能否启动？
		if (canStart()) {
			di.setStatus(STATUS_PREPARE_TO_DOWNLOAD);
			updateDatabase(di);
			dt = new DownloadThread(this, dlId, dlUrl, this, DownloadUtils.getDownloadApkFilePathById(dlId), 0);
			mDownloads.put(dlId, dt);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadChanged(di);
				}
			}
			dt.start();
		}
		StatisticsAgent.onEvent(getApplicationContext(), new startDownloadEvent(source, pkgName));
	}

	void removeOutofDateDownloads(String pkgName) {
		if (TextUtils.isEmpty(pkgName)) {
			return;
		}

		List<DownloadItem> list = getDownloadsByPkgName(pkgName);
		if (list == null || list.size() == 0) {
			return;
		}

		for (DownloadItem di : list) {
			removeDownloadImmediately(di.getId());
		}
	}

	void removeDownload(String dlId) {
		if (TextUtils.isEmpty(dlId)) {
			Log.w(TAG, "stop id is empty");
			return;
		}

		DownloadItem di = getDownloadById(dlId);
		if (di == null) {
			Log.w(TAG, "stop id:" + dlId + " not in db");
			return;
		}
		DownloadThread dt = mDownloads.get(dlId);
		if (dt != null && dt.isDownloading()) {
			di.setStatus(STATUS_PREPARE_TO_STOP);
			di.setShouldRemove(true);
			updateDatabase(di);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadChanged(di);
				}
			}
			dt.stopDownload();
			Log.d(TAG, dlId + " is running. async remove");
		} else {
			// 没有运行，直接删除数据库就可以了
			DownloadDatabase db = DownloadDatabase.getInstance(this);
			db.deleteById(dlId);
			DownloadUtils.removeDownloadTmpFile(dlId);
			DownloadUtils.removeDownloadedFile(dlId);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadRemoved(dlId);
				}
			}
		}
	}

	/**
	 * 删除所有的安装成功的下载任务，不会触发回调
	 */
	int removeAllInstalled() {
		List<DownloadItem> all = getAllDownloads();
		Set<String> toRemove = new HashSet<String>();
		for (DownloadItem di : all) {
			if (PackageUtils.isPackageInstalled(this, di.getPkgName())) {
				toRemove.add(di.getId());
			}
		}
		if (toRemove.size() == 0) {
			return 0;
		}
		int count = 0;
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		for (String id : toRemove) {
			count += db.deleteById(id);
		}
		return count;
	}

	/**
	 * 删除所指定ID的一批下载任务，不会触发回调
	 */
	int removeAllInstalled(List<String> idList) {
		int count = 0;
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		for (String id : idList) {
			count += db.deleteById(id);
		}
		return count;
	}

	void startDownload(String dlId) {
		startDownload(dlId, true);
	}

	void stopDownload(String dlId) {
		if (TextUtils.isEmpty(dlId)) {
			Log.w(TAG, "stop id is empty");
			return;
		}
		DownloadItem di = getDownloadById(dlId);
		if (di == null) {
			Log.w(TAG, "stop id:" + dlId + " not in db");
			return;
		}
		if (di.getStatus() == STATUS_PAUSED_BY_USER) {
			Log.w(TAG, dlId + "already stopped");
			return;
		}

		DownloadThread dt = mDownloads.get(dlId);
		// 如果任务仍然在运行，那么停止任务，然后等待回调
		// 否则直接更新数据库然后回调
		if (dt != null && dt.isDownloading()) {
			Log.d(TAG, dlId + " is running");
			di.setStatus(STATUS_PREPARE_TO_STOP);
			updateDatabase(di);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadChanged(di);
				}
			}
			dt.stopDownload();
		} else {
			di.setStatus(STATUS_PAUSED_BY_USER);
			File tmp = new File(DownloadUtils.getDownloadApkTmpFilePathById(dlId));
			di.setDownloadedSize(tmp.length());
			updateDatabase(di);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadChanged(di);
				}
			}
		}

	}

	List<DownloadItem> getAllDownloadsOrderBy(String colName, boolean isDesc) {
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		Cursor cur = null;
		try {
			List<DownloadItem> list = new ArrayList<DownloadItem>();
			if (isDesc) {
				cur = db.query(null, null, colName + " DESC");
			} else {
				cur = db.query(null, null, colName + " ASC");
			}

			for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
				DownloadItem di = DownloadDatabase.buildFromCursor(cur);
				if (di != null) {
					list.add(di);
				} else {
					Log.w(TAG, "DownloadItem is null");
				}
			}
			return list;
		} finally {
			if (cur != null) {
				cur.close();
			}
		}
	}

	void addFileDownloadListener(FileDownloadListener listener) {
		if (listener == null) {
			Log.w(TAG, "addFileDownloadListener:listener is null");
			return;
		}
		mListeners.add(listener);
	}

	void removeFileDownloadListener(FileDownloadListener listener) {
		if (listener == null) {
			Log.w(TAG, "removeFileDownloadListener:listener is null");
			return;
		}
		if (mListeners.contains(listener)) {
			mListeners.remove(listener);
		} else {
			Log.w(TAG, "invalid listener");
		}
	}

	DownloadItem getDownloadById(String id) {
		DownloadItem di = null;
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		Cursor cur = null;
		try {
			cur = db.query(DownloadDatabase.COL_DL_ID + "='" + id + "'", null, null);
			if (cur.moveToFirst()) {
				di = DownloadDatabase.buildFromCursor(cur);
			}
			return di;
		} finally {
			if (cur != null) {
				cur.close();
			}
		}
	}

	void installApk(final DownloadItem di) {
		if (di == null || TextUtils.isEmpty(di.getId())) {
			return;
		}
		// 1.尝试pm 命令安装
		// 2.如果1失败，则调系统安装界面安装
		final String path = DownloadUtils.getDownloadApkFilePathById(di.getId());
		if (DownloadUtils.canInstall(this)) {
			Command installCmd = new Command("pm install " + path);
			installCmd.setListener(new CommandListener() {
				@Override
				public void onCommandDone(int exitCode, ArrayList<String> output) {
					mInstallingTask.remove(di.getPkgName());
					boolean success = false;
					for (String line : output) {
						if ("Success".equalsIgnoreCase(line)) {
							success = true;
							StatisticsAgent.onEvent(getApplicationContext(),
									new installEvent(di.getSource(), di.getPkgName(), "pm"));
							myUmengStaticstics.installapk(getApplicationContext(), di.getSource(), di.getPkgName(),
									"pm");
							break;
						}
					}
					if (success) {
						return;
					}

					if (PackageUtils.launchInstall(DownloadService.this, path)) {
						StatisticsAgent.onEvent(getApplicationContext(),
								new installEvent(di.getSource(), di.getPkgName(), "user"));
						myUmengStaticstics.installapk(getApplicationContext(), di.getSource(), di.getPkgName(), "user");
					}
				}

			});
			mInstallingTask.add(di.getPkgName());
			di.setStatus(STATUS_INSTALLING);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadChanged(di);
				}
			}

			installCmd.start();

		} else {
			if (PackageUtils.launchInstall(DownloadService.this, path)) {
				StatisticsAgent.onEvent(getApplicationContext(),
						new installEvent(di.getSource(), di.getPkgName(), "user"));
				myUmengStaticstics.installapk(getApplicationContext(), di.getSource(), di.getPkgName(), "user");
			}
		}

	}

	int getDownloadStatus(String pkgName, int verCode) {
		if (pkgName.equals(getPackageName())) { // 判断应用市场自己的下载状态（应用市场的自升级情况）
			return getOwnDownloadStatus();
		}

		AppUpdateModel aum = getAppUpdateByPkgName(pkgName);
		if (aum == null) {
			if (PackageUtils.isPackageInstalled(this, pkgName)) {
				return DownloadService.STATUS_INSTALLED;
			}

			// 上层处理out_of_date状态时，确保将过期任务删除，从而确保在下载管理数据库中相同包名的任务只有一个。
			// 所以本函数中，可以信任 getDownloadByPkgName(pkgName) 返回的内容，因为只有一个。下面的调用同理。
			DownloadItem di = getDownloadByPkgName(pkgName);
			if (di == null) {
				return DownloadService.STATUS_NO_STATUS;
			}

			if (verCode == di.getVersionCode()) {
				return getNormalDownloadStatus(di);
			} else {
				return DownloadService.STATUS_DOWNLOAD_OUT_OF_DATE;
			}
		}

		if (!PackageUtils.isPackageInstalled(this, pkgName)) {
			DownloadItem di = getDownloadByPkgName(pkgName);
			if (di == null) {
				return DownloadService.STATUS_NO_STATUS;
			}

			if (verCode == di.getVersionCode()) {
				return getNormalDownloadStatus(di);
			} else {
				return DownloadService.STATUS_DOWNLOAD_OUT_OF_DATE;
			}
		}

		// 获取检测任务的安装版本号
		int curVerisonCode = 0;
		PackageManager manager = getPackageManager();
		try {
			PackageInfo info = manager.getPackageInfo(pkgName, 0);
			curVerisonCode = info.versionCode; // 版本名
		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}

		if (curVerisonCode >= aum.getVersionCode()) {
			return DownloadService.STATUS_INSTALLED;
		}

		if (verCode >= aum.getVersionCode()) {
			DownloadItem di = getDownloadByPkgName(pkgName);
			if (di == null) {
				return DownloadService.STATUS_NEED_TO_UPDATE;
			}

			if (di.getVersionCode() != verCode) {
				return DownloadService.STATUS_DOWNLOAD_OUT_OF_DATE;
			}

			return getNormalDownloadStatus(di);

		} else /* if(verCode < aum.getVersionCode()) */ {
			if (verCode > curVerisonCode) {
				DownloadItem di = getDownloadByPkgName(pkgName);
				if (di == null) {
					return DownloadService.STATUS_NEED_TO_UPDATE;
				}

				if (di.getVersionCode() != verCode) {
					return DownloadService.STATUS_DOWNLOAD_OUT_OF_DATE;
				}
				return getNormalDownloadStatus(di);
			} else {
				return DownloadService.STATUS_INSTALLED;
			}
		}
	}

	// ///////////////////////////////////////////////////////////////////////////////
	// 以上函数通过DownloadActivity对外提供，仅供继承与DownloadActivity的Activity使用//
	// //////////////////////////////////////////////////////////////////////////////

	/*
	 * 立即删除下载任务: 1.在数据库中删除 2.在正下载map中去除 3.同步完成,不促发回调
	 */
	private void removeDownloadImmediately(String dlId) {
		if (TextUtils.isEmpty(dlId)) {
			return;
		}

		DownloadThread dt = mDownloads.get(dlId);
		if (dt != null && dt.isDownloading()) {
			dt.stopDownload();
			mDownloads.remove(dlId);
		}

		DownloadItem di = getDownloadById(dlId);
		if (di != null) {
			DownloadDatabase db = DownloadDatabase.getInstance(this);
			db.deleteById(dlId);
			DownloadUtils.removeDownloadTmpFile(dlId);
			DownloadUtils.removeDownloadedFile(dlId);
		}
	}

	// private functions///
	private synchronized boolean canStart() {
		// 删除下载同时删除了task
		// 停止下载的时候没有删除task
		// 所以只需要只需：总任务-正在停止的任务,即是正在运行的任务

		if (!DownloadUtils.isNetworkAvailable(this)) {
			Log.d(TAG, "no available network");
			return false;
		}
		int count = mDownloads.size();
		for (String dlId : mDownloads.keySet()) {
			DownloadThread dt = mDownloads.get(dlId);
			if (dt.shouldStop()) {
				count--;
			}
		}
		return count < MAX_DOWNLOAD;
	}

	private List<DownloadItem> getAllDownloads() {
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		Cursor cur = null;
		try {
			List<DownloadItem> list = new ArrayList<DownloadItem>();
			cur = db.query(null, null, DownloadDatabase.COL_LAST_MODIFICATION + " DESC");
			for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
				DownloadItem di = DownloadDatabase.buildFromCursor(cur);
				if (di != null) {
					list.add(di);
				} else {
					Log.w(TAG, "DownloadItem is null");
				}
			}
			return list;
		} finally {
			if (cur != null) {
				cur.close();
			}
		}
	}

	private void startDownload(String dlId, boolean resetRetryCount) {
		if (TextUtils.isEmpty(dlId)) {
			Log.w(TAG, "start id is empty");
			return;
		}

		DownloadItem di = getDownloadById(dlId);
		if (di == null) {
			Log.w(TAG, "start id:" + dlId + " not in db");
			return;
		}
		if (resetRetryCount) {
			di.setRetryCount(0);
		}
		myUmengStaticstics.continueDownload(getApplicationContext(), di.getSource(), di.getPkgName());
		// change database state
		DownloadThread dt = mDownloads.get(dlId);
		if (dt != null) {
			Log.w(TAG, dlId + " should not in running task");
			mDownloads.remove(dlId);
			dt.setDownloadListener(null);
			dt.stopDownload();
		}
		if (canStart()) {
			di.setStatus(STATUS_PREPARE_TO_DOWNLOAD);
			updateDatabase(di);
			dt = new DownloadThread(this, dlId, di.getDlUrl(), this, DownloadUtils.getDownloadApkFilePathById(dlId), 0);
			mDownloads.put(dlId, dt);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadChanged(di);
				}
			}
			dt.start();
		} else {
			di.setStatus(STATUS_PENDING);
			updateDatabase(di);
			if (mListeners != null) {
				for (FileDownloadListener l : mListeners) {
					l.onDownloadChanged(di);
				}
			}
		}
	}

	private DownloadItem getDownloadByPkgName(String pkgName) {
		DownloadItem di = null;
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		Cursor cur = null;

		try {
			cur = db.query(DownloadDatabase.COL_PKG_NAME + "='" + pkgName + "'", null, null);
			if (cur.moveToFirst()) {
				di = DownloadDatabase.buildFromCursor(cur);
			}
			return di;
		} finally {
			if (cur != null) {
				cur.close();
			}
		}
	}

	private List<DownloadItem> getDownloadsByPkgName(String pkgName) {
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		Cursor cur = null;

		try {
			List<DownloadItem> list = new ArrayList<DownloadItem>();
			cur = db.query(DownloadDatabase.COL_PKG_NAME + "='" + pkgName + "'", null, null);
			for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
				DownloadItem di = DownloadDatabase.buildFromCursor(cur);
				if (di != null) {
					list.add(di);
				}
			}

			return list;
		} finally {
			if (cur != null) {
				cur.close();
			}
		}
	}

	private AppUpdateModel getAppUpdateByPkgName(String pkgName) {
		AppUpdateDatabase db = AppUpdateDatabase.getInstance(this);
		return db.get(pkgName);
	}

	private synchronized void startNext() {
		if (!DownloadUtils.isWifiConnected(this)) {
			Log.d(TAG, "wifi not connected");
			return;
		}
		if (!canStart()) {
			Log.d(TAG, "cannot startNext");
			return;
		}
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		Cursor cur = null;
		try {
			cur = db.query(null, null, DownloadDatabase.COL_LAST_MODIFICATION + " DESC");
			int indexStatus = cur.getColumnIndex(DownloadDatabase.COL_STATUS);
			int indexDlid = cur.getColumnIndex(DownloadDatabase.COL_DL_ID);
			for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
				int status = cur.getInt(indexStatus);
				String dlId = cur.getString(indexDlid);
				if (status == STATUS_PENDING) {
					startDownload(dlId, false);
				}
				if (status == STATUS_PAUSED_BY_ERROR) {
					int retry = cur.getInt(cur.getColumnIndex(DownloadDatabase.COL_RETRY_COUNT));
					if (retry < MAX_RETRY_COUNT) {
						startDownload(dlId, false);
					} else {
						Log.w(TAG, dlId + " reaches max retry count");
					}
				}
				if (!canStart()) {
					break;
				}
			}
		} finally {
			if (cur != null) {
				cur.close();
			}
		}
	}

	private long insertToDatabase(String dlUrl, String name, String pkgName, String versionName, int versionCode,
			String md5, String iconUrl, int priority, String source, boolean hidden) {
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		ContentValues cv = new ContentValues();
		cv.put(DownloadDatabase.COL_DL_ID, DownloadUtils.generateDownloadId(pkgName, versionCode));
		cv.put(DownloadDatabase.COL_DL_URL, dlUrl);
		cv.put(DownloadDatabase.COL_NAME, name);
		cv.put(DownloadDatabase.COL_STATUS, STATUS_PENDING);
		cv.put(DownloadDatabase.COL_DOWNLOADED_SIZE, 0);
		cv.put(DownloadDatabase.COL_TOTAL_SIZE, 0);
		cv.put(DownloadDatabase.COL_RETRY_COUNT, 0);
		cv.put(DownloadDatabase.COL_PKG_NAME, pkgName);
		cv.put(DownloadDatabase.COL_VERSION_NAME, versionName);
		cv.put(DownloadDatabase.COL_VERSION_CODE, versionCode);
		cv.put(DownloadDatabase.COL_MD5, md5);
		cv.put(DownloadDatabase.COL_ICON_URL, iconUrl);
		cv.put(DownloadDatabase.COL_PRIORITY, priority);
		cv.put(DownloadDatabase.COL_SOURCE, source);
		cv.put(DownloadDatabase.COL_SHOULD_REMOVE, 0);
		cv.put(DownloadDatabase.COL_HIDDEN, hidden ? 1 : 0);
		return db.insert(cv);
	}

	private int updateDatabase(DownloadItem di) {
		DownloadDatabase db = DownloadDatabase.getInstance(this);
		ContentValues cv = new ContentValues();
		String id = DownloadUtils.generateDownloadId(di.getPkgName(), di.getVersionCode());
		cv.put(DownloadDatabase.COL_DL_ID, id);
		cv.put(DownloadDatabase.COL_DL_URL, di.getDlUrl());
		cv.put(DownloadDatabase.COL_NAME, di.getName());
		cv.put(DownloadDatabase.COL_STATUS, di.getStatus());
		cv.put(DownloadDatabase.COL_DOWNLOADED_SIZE, di.getDownloadedSize());
		cv.put(DownloadDatabase.COL_TOTAL_SIZE, di.getTotalSize());
		cv.put(DownloadDatabase.COL_RETRY_COUNT, di.getRetryCount());
		cv.put(DownloadDatabase.COL_PKG_NAME, di.getPkgName());
		cv.put(DownloadDatabase.COL_VERSION_NAME, di.getVersionName());
		cv.put(DownloadDatabase.COL_VERSION_CODE, di.getVersionCode());
		cv.put(DownloadDatabase.COL_MD5, di.getMd5());
		cv.put(DownloadDatabase.COL_AUTO_INSTALL, di.getAutoInstall());
		cv.put(DownloadDatabase.COL_ICON_URL, di.getIconUrl());
		cv.put(DownloadDatabase.COL_SOURCE, di.getSource());
		cv.put(DownloadDatabase.COL_PRIORITY, di.getPriority());
		cv.put(DownloadDatabase.COL_SHOULD_REMOVE, di.isShouldRemove() ? 1 : 0);
		cv.put(DownloadDatabase.COL_HIDDEN, di.isHidden() ? 1 : 0);
		return db.update(id, cv);
	}

	private int getNormalDownloadStatus(DownloadItem di) {
		// 如果下载的临时文件已经存在，则认为下载已经完成或者正在安装
		File file = new File(DownloadUtils.getDownloadApkFilePathById(di.getId()));
		if (file.exists()) {
			if (di.getStatus() == DownloadService.STATUS_INSTALLING) {
				return DownloadService.STATUS_INSTALLING;
			} else {
				return DownloadService.STATUS_CAN_INSTALL;
			}
		}

		// 流程到这里，只有这几个状态是合理的，其余状态均认为是错误的。
		if (di.getStatus() == DownloadService.STATUS_PAUSED_BY_USER
				|| di.getStatus() == DownloadService.STATUS_PAUSED_BY_ERROR
				|| di.getStatus() == DownloadService.STATUS_PAUSED_BY_MOBILE_NETWORK
				|| di.getStatus() == DownloadService.STATUS_PENDING || isDownloading(di)) {
			return di.getStatus();

		} else {
			LogUtil.d(TAG, "DownloadService.STATUS_PAUSED_BY_ERROR " + DownloadService.getStatusString(di.getStatus()));
			return DownloadService.STATUS_PAUSED_BY_ERROR;
		}
	}

	private int getOwnDownloadStatus() {
		DownloadItem di = getDownloadByPkgName(getPackageName());
		if (di == null) {
			return DownloadService.STATUS_NO_STATUS;
		}

		int curVerisonCode = 0;
		PackageManager manager = getPackageManager();
		try {
			PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
			curVerisonCode = info.versionCode; // 版本名
		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}

		// 如果当前安装的版本比数据库中将要下载的版本高或者相同，则认为无需下载，安装版本直接可用
		if (di.getVersionCode() <= curVerisonCode) {
			return DownloadService.STATUS_INSTALLED;
		}

		return getNormalDownloadStatus(di);
	}

	// ////////////////////////////////////////////////////////////////////////////////
	// 以下为：应用市场自更新使用的相关代码
	// /////////////////////////////////////////////////////////////////////////////////

	private void addDownload(DownloadItem item, boolean isOpenDownLoadMgr) {
		if (item == null) {
			return;
		}
		// String dlId = DownloadUtils.generateDownloadId(item.getPkgName(),
		// item.getVersionCode());
		int status = getDownloadStatus(item.getPkgName(), item.getVersionCode());
		switch (status) {
		case DownloadService.STATUS_CAN_INSTALL:
			installApk(item);
			break;
		case DownloadService.STATUS_NO_STATUS:
			addDownload(item.getDlUrl(), item.getName(), item.getPkgName(), item.getVersionName(),
					item.getVersionCode(), item.getMd5(), item.getIconUrl(), item.getSource(), item.getPriority(),
					item.isHidden());

			if (isOpenDownLoadMgr) {
				Toast.makeText(this, R.string.upgrade_now_toast, Toast.LENGTH_SHORT).show();
				Intent intent = new Intent(this, DownloadManagerActivity.class);
				intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
				startActivity(intent);
			} else {
				Toast.makeText(this, R.string.upgrade_now_toast, Toast.LENGTH_SHORT).show();
			}

			break;
		default:
			Toast.makeText(this, R.string.upgrade_now_toast, Toast.LENGTH_SHORT).show();
			break;
		}
	}

	private void registerBroadcastReceiver() {
		IntentFilter filter = new IntentFilter();
		filter.addAction(UpdateService.ACTION_CHECK_DL_UPGRADE);
		registerReceiver(mCheckDlUpgradeReceiver, filter);
	}

	private class CheckDlUpgradeReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent == null) {
				return;
			}
			if (UpdateService.ACTION_CHECK_DL_UPGRADE.equals(intent.getAction())) {
				CardUpgrade cardUpgrade = (CardUpgrade) intent.getSerializableExtra(UpdateService.EXTRA_UPGRADE_INFO);
				if (cardUpgrade == null) {
					return;
				}
				Upgrade upgrade = cardUpgrade.getUpgrade();
				if (upgrade == null) {
					return;
				}
				// 检查数据库中是否有旧版本的升级的记录，如果有，删除数据库中记录和下载内容
				DownloadDatabase db = DownloadDatabase.getInstance(DownloadService.this);
				Cursor cur = null;
				try {
					cur = db.query(DownloadDatabase.COL_PKG_NAME + "=?", new String[] { getPackageName() }, null);
					for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
						int versionCode = cur.getInt(cur.getColumnIndex(DownloadDatabase.COL_VERSION_CODE));
						String dlId = cur.getString(cur.getColumnIndex(DownloadDatabase.COL_DL_ID));
						if (versionCode < upgrade.getVersionCode()) {
							removeDownload(dlId);
						}
					}
				} finally {
					if (cur != null) {
						cur.close();
					}
				}
			}
		}
	}
	// ////////////////////////////////////////////////////////////////////////////////
	// 以上为：应用市场自更新使用的相关代码
	// /////////////////////////////////////////////////////////////////////////////////
}